import { BrowserWindow, ipcMain, type IpcMainEvent, type WebContents } from 'electron'
import type {
  GetBrowserTabsParam,
  ToBrowserMainMap,
  ToLayoutRendererMap
} from '~types/message-channel'
import { topicPrefix } from '~types/message-channel'

/**
 * 主进程与渲染进程的通用 IPC 帮助器
 * - on: 监听渲染进程发往主进程的异步消息
 * - syncOn: 监听渲染进程发往主进程的同步消息，并通过 returnValue 返回
 * - send: 主进程发送消息到渲染进程
 */
export function createBrowserIpc(webContents: WebContents) {
  // 目标窗口ID（用于限定只处理同一窗口内的所有视图发来的消息）
  const getOwnerWindowId = (wc: WebContents) => {
    try {
      const win = BrowserWindow.fromWebContents(wc)
      return win?.id
    } catch {
      return null
    }
  }

  // 统一清理：只为该 createBrowserIpc 实例添加一次 destroyed 监听，销毁时批量 off
  const subscriptions: Array<{
    channel: string
    handler: (e: IpcMainEvent, ...args: any[]) => void
  }> = []

  webContents.once('destroyed', () => {
    for (const { channel, handler } of subscriptions) {
      ipcMain.off(channel, handler)
    }
    subscriptions.length = 0
  })

  return {
    on<T extends keyof ToBrowserMainMap>(topic: T, cb: (...args: ToBrowserMainMap[T]) => void) {
      const channel = topicPrefix + topic
      const handler = (e: IpcMainEvent, ...args: ToBrowserMainMap[T]) => {
        const senderWindowId = getOwnerWindowId(e.sender)
        const targetWindowId = getOwnerWindowId(webContents)

        if (e.sender === webContents || senderWindowId === targetWindowId) {
          cb(...args)
        }
      }
      ipcMain.on(channel, handler)
      subscriptions.push({ channel, handler })
    },

    syncOn<T extends keyof GetBrowserTabsParam>(
      topic: T,
      cb: (...args: GetBrowserTabsParam[T]['params']) => GetBrowserTabsParam[T]['result']
    ) {
      const channel = topicPrefix + topic
      const handler = (e: IpcMainEvent, ...args: GetBrowserTabsParam[T]['params']) => {
        const senderWindowId = getOwnerWindowId(e.sender)
        const targetWindowId = getOwnerWindowId(webContents)
        if (e.sender === webContents || senderWindowId === targetWindowId) {
          e.returnValue = cb(...args)
        }
      }
      ipcMain.on(channel, handler)
      subscriptions.push({ channel, handler })
    },

    send<T extends keyof ToLayoutRendererMap>(topic: T, ...data: ToLayoutRendererMap[T]) {
      webContents.send(topicPrefix + topic, ...data)
    }
  }
}
